package com.gthncz.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.gthncz.filter.JwtAuthenticationFilter;
import com.gthncz.filter.JwtLoginFilter;
import com.gthncz.service.TokenAuthenticationProvider;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		super.configure(auth);
		// auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
		auth.authenticationProvider(authenticationProvider()); // 内部是一个 List，可以添加多个 AuthenticationProvider
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		super.configure(web);
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// super.configure(http);
		http.csrf().disable()
			// 对请求进行认证
			.authorizeRequests()
			// 放行所有 / 路径访问
			.antMatchers("/").permitAll()
			// 放行所有 OPTIONS 操作
			.antMatchers(HttpMethod.OPTIONS).permitAll()
			// 测试用，放开 /users 路径访问
			.antMatchers("/users").permitAll()
			// 添加权限检测
			.antMatchers("/hello").hasAuthority("AUTH_WRITE")
			// 添加角色检测, role should not start with 'ROLE_' since it is automatically inserted. Got 'ROLE_ADMIN'
			.antMatchers("/world").hasRole("ADMIN")
			// 放行 /login 的 POST 类型操作
			.antMatchers(HttpMethod.POST, "/login").permitAll()
			// 其他所有请求均需要认证
			.anyRequest().authenticated();
		
		/* 添加两个 Filter */
		//// 添加一个过滤器 所有访问 /login 的请求交给 JWTLoginFilter 来处理 这个类处理所有的JWT相关内容
		http.addFilterBefore(jwtLoginFilter(), UsernamePasswordAuthenticationFilter.class);
		// 添加一个过滤器验证其他请求的Token是否合法
		http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
	}
	
	// 这样写，否则 Filter 中的 JwtAuthenticationService 不能注册
	@Bean
	protected JwtLoginFilter jwtLoginFilter() throws Exception {
		return new JwtLoginFilter("/login", authenticationManagerBean());
	}

	@Bean
	protected JwtAuthenticationFilter jwtAuthenticationFilter() {
		return new JwtAuthenticationFilter();
	}
	
	@Bean
	protected TokenAuthenticationProvider authenticationProvider() {
		return new TokenAuthenticationProvider();
	}
	
	@Bean
	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}
	
	// 解决 java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id " 问题
	@Bean
	PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}

}
